Skip to content

在 Entity Framework Core(EF Core)中,Data Annotation(数据注解 / 数据特性) 是一种通过在实体类的属性或类上添加 [Attribute] 来配置模型映射的方式。虽然不如 Fluent API 灵活,但对于简单场景非常直观。

以下是 最常用的数据注解(Data Annotations) 及其作用说明:


📌 1. 表与架构配置

特性作用示例
[Table("TableName")]指定数据库表名[Table("Sys_User")]
[Table("TableName", Schema = "dbo")]指定表名和数据库 Schema[Table("Users", Schema = "auth")]

📌 2. 主键与标识生成

特性作用示例
[Key]标记为主键(当属性名不是 Id<ClassName>Id 时必需)[Key] public int UserId { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]数据库自动生成值(如自增)[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]值由程序提供(对应 .ValueGeneratedNever()[DatabaseGenerated(DatabaseGeneratedOption.None)]
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]值由数据库计算生成(如触发器、默认值函数)

⚠️ 注意:long Id + 自增 → 用 Identity;雪花 ID / 手动赋值 → 用 None


📌 3. 列配置

特性作用示例
[Column("ColumnName")]指定列名[Column("user_name")]
[Column(TypeName = "varchar(50)")]指定数据库列类型[Column(TypeName = "nvarchar(100)")]
[MaxLength(100)]设置最大长度(字符串/数组)[MaxLength(255)] public string Name { get; set; }
[StringLength(100)]MaxLength,但仅用于字符串[StringLength(50)]

💡 MaxLengthStringLength 都会生成数据库约束(如 nvarchar(100)),也会在验证时生效(配合 ModelState.IsValid)。


📌 4. 必填与非空约束

特性作用示例
[Required]表示该字段不可为 null(非空)[Required] public string Email { get; set; }

⚠️ 对 值类型(如 int, DateTime)无效,因为它们本身不能为 null。
若想让值类型可空且必填,请用 int? + [Required]


📌 5. 默认值(⚠️ EF Core 限制)

重要:EF Core 不支持通过 Data Annotation 设置数据库默认值!
必须使用 Fluent API.HasDefaultValue(...)

但你可以用以下方式“模拟”应用层默认值:

csharp
public class User
{
    [Required]
    public bool IsActive { get; set; } = true; // C# 层默认值
}

但这不会生成 SQL 的 DEFAULT (1),除非你在 Fluent API 中显式配置。


📌 6. 唯一约束(EF Core 5+)

特性作用示例
[Index(nameof(Email), IsUnique = true)]在类上定义唯一索引(EF Core 5+)见下方完整示例
csharp
[Index(nameof(Email), IsUnique = true)]
public class User
{
    public int Id { get; set; }
    public string Email { get; set; }
}

⚠️ 注意:[Index]类级别 特性,不是属性级别。


📌 7. 时间戳 / 并发控制

特性作用
[Timestamp]标记为并发令牌(通常用于 byte[] 字段)
csharp
[Timestamp]
public byte[] RowVersion { get; set; }

等价于 Fluent API:.IsRowVersion()


📌 8. 忽略属性(不映射到数据库)

特性作用示例
[NotMapped]该属性不参与数据库映射[NotMapped] public string FullName => $"{FirstName} {LastName}";

📌 9. 外键关系(较少用,推荐 Fluent API)

特性作用
[ForeignKey("PropertyName")]显式指定外键属性
[InverseProperty("PropertyName")]解决双向导航属性歧义

💡 实际开发中,复杂关系建议用 Fluent API 配置更清晰。


✅ 完整示例:UserEntity 使用 Data Annotations

csharp
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

[Table("Sys_User")]
[Index(nameof(Email), IsUnique = true)]
public class UserEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)] // 手动赋值 ID
    [Column(TypeName = "bigint")]
    public long Id { get; set; }

    [Required, MaxLength(50)]
    public string UserName { get; set; }

    [Required, MaxLength(100)]
    public string Email { get; set; }

    [Column(TypeName = "bit")]
    public bool IsActive { get; set; } = true;

    [NotMapped]
    public string DisplayName => $"User: {UserName}";

    // 外键示例(可选)
    public long DepartmentId { get; set; }

    [ForeignKey("DepartmentId")]
    public DepartmentEntity Department { get; set; }
}

🔚 总结:常用 Data Annotations 速查表

功能特性
表名[Table("...")]
主键[Key]
自增/手动ID[DatabaseGenerated(...)]
列名/类型[Column("...", TypeName = "...")]
长度限制[MaxLength(n)] / [StringLength(n)]
非空[Required]
唯一索引[Index(..., IsUnique = true)](类上)
不映射[NotMapped]
并发控制[Timestamp]

📝 最佳实践建议:

  • 简单项目:可用 Data Annotations,代码直观;
  • 中大型项目:推荐 Fluent APIOnModelCreating),保持实体类干净,配置集中,功能更强;
  • 混合使用:可以同时用,但避免冲突(Fluent API 优先级更高)。

如有具体场景,我可以帮你选择更适合的方式!